<?php
/**
 * Created by ephp
 * User: 22071
 * Date: 2019/6/17
 * Email: <zhendongdong@foxmail.com>
 */

namespace paper\support;


use paper\captcha\Captcha;

class Validate
{
    private $rule = [];
    private $errMsg = '';
    private $data;
    //设置规则应用范围
    private $scope = null;
    private $message = [
        'require'   => '%s 不能为空',
        'number'    => '%s 只能是数字',
        'phone'     => '%s 不是有效的手机号码',
        'mail'      => '%s 不是邮箱的邮箱格式',
        'bool'      => '%s 只能是布尔值',
        'array'     => '%s 只能是数组',
        'integer'   => '%s 只能是整形',
        'length'    => '%s 长度错误',
        'max'       => '%s 数字太大',
        'min'       => '%s 数字太小',
        'url'       => '%s 不是邮箱的url',
        'ip'        => '%s 不是有效的IP地址',
        'alphaDash' => '%s 只能只字母数组与 - 和 _ 符号',
        'alphaNum'  => '%s 只能是字母与数字',
        'captcha'   => '%s 验证码错误',
    ];
    private $userMessage = [

    ];


    public function __construct($rule = [])
    {
        $this->rule = $rule;
    }

    /**
     * @return array
     */
    public function rules(): array
    {
        return $this->rule;
    }

    /**
     * @return null
     */
    public function getScope()
    {
        return $this->scope;
    }

    /**
     * @param null $scope
     */
    public function setScope($scope): void
    {
        $this->scope = $scope;
    }

    /**
     * 设置规则
     * @param $rule
     */
    public function setRule($rule)
    {
        $this->rule = array_merge($this->rule, $rule);
    }

    /**
     * 获取错误信息
     * @return string
     */
    public function getErrMsg()
    {
        return $this->errMsg;
    }

    /**
     * @param string $field
     * @param string $rule
     */
    private function setErrMsg(string $field, string $rule): void
    {
        $userField = "{$field}.{$rule}";
        if (array_key_exists($userField, $this->userMessage)) {
            $this->errMsg = str_replace("%s", $field, $this->userMessage[$userField]);
        } else {
            if (array_key_exists($rule, $this->message)) {
                $this->errMsg = str_replace("%s", $field, $this->message[$rule]);
            } else {
                $this->errMsg = $field . '数据不合法';
            }
        }
    }


    /**
     * 设置用户自定义错误消息
     * @param array $message
     */
    public function setMessage(array $message): void
    {
        $this->userMessage = $message;
    }

    /**
     * 判断是否是手机号码
     * @param $value
     * @return bool
     */
    protected function validatePhone($value)
    {
        if (preg_match("/^1[23456789]{1}\d{9}$/", $value)) {
            return true;
        }
        return false;
    }

    /**
     * 验证图像验证码
     * @param $value
     * @return bool
     */
    protected function validateCaptcha($value)
    {
        return (new Captcha())->validate($value);
    }

    /**
     * 判断是否是整形
     * @param $value
     * @return bool
     */
    protected function validateInteger($value): bool
    {
        //is_int 只能判断变量是否整形但是不能判断字符串
        return is_numeric($value) && is_int($value + 0);
    }

    /**判断最大值
     * @param $value
     * @param $params
     * @return bool
     */
    protected function validateMax($value, $params): bool
    {
        $params = (int)$params;
        return $value <= $params;
    }

    /**判断最小值
     * @param $value
     * @param $params
     * @return bool
     */
    protected function validateMin($value, $params): bool
    {
        $params = (int)$params;
        return $value >= $params;
    }

    /**
     * 判断是否邮箱
     * @param $value
     * @return bool
     */
    protected function validateMail($value): bool
    {
        return filter_var($value, FILTER_VALIDATE_EMAIL) ? true : false;
    }

    /**
     * 判断是否url
     * @param $value
     * @return bool
     */
    protected function validateUrl($value): bool
    {
        return filter_var($value, FILTER_VALIDATE_URL) ? true : false;
    }

    /**
     * 判断是否字母+数字+_-
     * @param $value
     * @return bool
     */
    protected function validateAlphaDash($value): bool
    {
        return preg_match('/^([0-9a-zA-Z_\-]+)$/', $value);
    }

    /**
     * 判断是否字母+数字
     * @param $value
     * @return bool
     */
    protected function validateAlphaNum($value): bool
    {
        return preg_match('/^([0-9a-zA-Z]+)$/', $value);
    }

    /**
     * 判断是是数组
     * @param $value
     * @return bool
     */
    protected function validateArray($value): bool
    {
        return is_array($value);
    }

    /**
     * 验证长度，若为数组则验证数组元素数，参数只有一个则判断是否相等
     * @param $value
     * @param $params
     * @return bool
     */
    protected function validateLength($value, $params): bool
    {
        $args   = explode(",", $params);
        $argc   = count($args);
        $length = 0;
        if (is_string($value)) {
            $length = mb_strlen($value);
        } else if (is_array($value)) {
            $length = count($value);
        }
        if ($argc == 2) {
            return $args[0] <= (int)$length && $length <= (int)$args[1];
        }
        return $args[0] === $length;
    }

    /**
     * 判断是否float
     * @param $value
     * @return bool
     */
    protected function validateFloat($value): bool
    {
        return filter_var($value, FILTER_VALIDATE_EMAIL) ? true : false;
    }

    /**判断是否布尔值
     * @param $value
     * @return bool
     */
    protected function validateBool($value): bool
    {
        return filter_var($value, FILTER_VALIDATE_BOOLEAN) ? true : false;
    }

    /**
     * 判断是否为IP
     * @param $value
     * @return bool
     */
    protected function validateIp($value): bool
    {
        return filter_var($value, FILTER_VALIDATE_IP) ? true : false;
    }

    /**
     * 判断是否是数字
     * @param $value
     * @return bool
     */
    protected function validateNumber($value): bool
    {
        return is_numeric($value);
    }

    private function getRules()
    {
        return $this->getScope() ? $this->rules()[$this->getScope()] : $this->rules();
    }

    /**批量检测数据是否合法
     * @param  $data
     * @return bool
     */
    public function check($data): bool
    {
        $this->data = $data;
        $rules      = $this->getRules();
        foreach ($rules as $filed => $rule) {
            if (!$this->valid($data[$filed] ?? null, $rule, $filed)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 验证数据 （不存在返回失败）
     * @param null $value
     * @param string $rule
     * @param null $filed
     * @return bool
     */
    public function requireValid($value = null, $rule = '', $filed = null)
    {
        return $this->valid($value, 'require|' . $rule, $filed);
    }

    /**
     * 验证数据 （普通验证）
     * @param null $value
     * @param string $rule
     * @param null $filed
     * @return bool
     */
    public function valid($value = null, $rule = '', $filed = null)
    {
        $rules = explode("|", $rule);
        if ($rules[0] == 'require') {
            if (null === $value) {
                $this->setErrMsg($filed, 'require');
                return false;
            }
            array_shift($rules);
        } else {
            if (!$value) {
                return true;
            }
        }
        foreach ($rules as $r) {
            $params = '';
            if (strpos($r, ":")) {
                [$r, $params] = explode(":", $r, 2);
            }
            $validate = 'validate' . ucfirst($r);
            if (!$this->$validate($value, $params)) {
                $this->setErrMsg($filed, $r);
                return false;
            }
        }
        return true;
    }
}